/*
 * Su-yun Information Technology, Co.,Ltd CONFIDENTIAL
 *
 * (C) Copyright Su-yun Information Technology, Co.,Ltd. 2021 All Rights Reserved.
 *
 * NOTICE:  All information contained herein is, and remains the property of
 * Su-yun Information Technology, Co.,Ltd. The intellectual property herein
 * are protected by trade secret, patent law or copyright law. Dissemination
 * of this information or reproduction of this material is strictly forbidden
 * unless prior written permission is obtained from Su-yun Information Technology.
 *
 * https://suyunplat.com/
 *
 */
package com.xtiim.battery.discharge.protocal;

import com.xtiim.battery.discharge.enums.BatteryGroupNoEnum;
import com.xtiim.battery.discharge.util.ByteUtil;
import com.xtiim.battery.discharge.util.TimeUtil;

import java.util.Date;

/**
 * Protocol command writer
 *
 */
public class CommandWriter {

    public static final byte EA = new Integer(0xEA).byteValue();
    public static final byte EC = new Integer(0xEC).byteValue();

    private static final byte COMMAND_DISCHARGE_START = 0;
    private static final byte COMMAND_DISCHARGE_STOP = 1;
    private static final byte COMMAND_TIMING = 0x18;
    private static final byte COMMAND_COLLECT = 0x19;
    private static final byte COMMAND_CLEAR_DATA = 0x1C;

    /**
     *
     * Compose command of start discharge.
     * Command format:
     *   0  1   2    3  4  5  6   7
     * |EA|len|host|00|00|cmd|EC|xor|
     *
     * @param host
     * @return
     */
    public byte[] startDischarge(int host) {
        byte[] bytes = new byte[8];
        bytes[0] = EA;
        bytes[1] = (byte) (bytes.length - 3);
        bytes[2] = (byte) host;
        bytes[3] = 0;
        bytes[4] = 0;
        bytes[5] = COMMAND_DISCHARGE_START;
        bytes[6] = EC;
        xor(bytes);

        return bytes;
    }

    /**
     *
     * Compose command of stop discharge.
     * Command format:
     *  0   1   2   3   4  5  6   7
     * |EA|len|host|00|00|cmd|EC|xor|
     *
     * @param host
     * @return
     */
    public byte[] stopDischarge(int host) {
        byte[] bytes = new byte[8];
        bytes[0] = EA;
        bytes[1] = (byte) (bytes.length - 3);
        bytes[2] = (byte) host;
        bytes[3] = 0;
        bytes[4] = 0;
        bytes[5] = COMMAND_DISCHARGE_STOP;
        bytes[6] = EC;
        xor(bytes);

        return bytes;
    }


    /**
     * Compose command of timing.
     * Command format:
     *  0   1   2    3 4  5 6 7 8 9 10 11 12 13
     * |EA|len|host|00|cmd|y|y|M|d|H|m|s|EC|xor|
     *
     * @return
     */
    public byte[] timing(int host) {
        byte[] bytes = new byte[14];
        bytes[0] = EA;
        bytes[1] = (byte) (bytes.length - 3);
        bytes[2] = (byte) host;
        bytes[3] = 0;
        bytes[4] = COMMAND_TIMING;
        String time = TimeUtil.dateToStr(new Date(), "yyyyMMddHHmmss");
        byte[] timeBytes = TimeUtil.time2byte(time);
        System.arraycopy(ByteUtil.dec2BCD(timeBytes), 0, bytes, 5, timeBytes.length);
        bytes[12] = EC;
        xor(bytes);

        return bytes;
    }

    /**
     *
     * Compose command of collecting.
     * Command format:
     *   0   1   2   3  4  5  6
     * |EA|len|host|00|cmd|EC|xor|
     *
     * @return
     */
    public byte[] collectRecord(int host) {
        byte[] bytes = new byte[7];
        bytes[0] = EA;
        bytes[1] = (byte) (bytes.length - 3);
        bytes[2] = (byte) host;
        bytes[3] = 0;
        bytes[4] = COMMAND_COLLECT;
        bytes[5] = EC;
        xor(bytes);

        return bytes;
    }

    /**
     * Compose command of clearing data.
     * Command format:
     *  0  1    2   3  4   5   6
     * |EA|len|host|00|cmd|EC|xor|
     *
     * @return
     */
    public byte[] clearData(int host) {
        byte[] bytes = new byte[7];
        bytes[0] = EA;
        bytes[1] = (byte) (bytes.length - 3);
        bytes[2] = (byte) host;
        bytes[3] = 0;
        bytes[4] = COMMAND_CLEAR_DATA;
        bytes[5] = EC;
        xor(bytes);

        return bytes;
    }

    /**
     * Compose command of sending control param.
     * Command format:
     *  0  1    2      3         4        5        6       7         8         9                10         11 12
     * |EA|len|host|address1|address2|current1|current1|voltage1|voltage1|dischargeCount1|dischargeCount2|EC|xor|
     *
     * @param host
     * @return
     */
    public byte[] controlParam(int host, int batteryGroupNo, double current, double voltage, int dischargeCount) {
        byte[] bytes = new byte[13];
        bytes[0] = EA;
        bytes[1] = (byte) (bytes.length - 3);
        bytes[2] = (byte) host;
        assignAddress(bytes, BatteryGroupNoEnum.getAddress(batteryGroupNo));
        byte[] currentBytes = ByteUtil.double2BCDOf2Bytes(current, 4);
        System.arraycopy(currentBytes, 0, bytes, 5, currentBytes.length);
        byte[] voltageBytes = ByteUtil.double2BCDOf2Bytes(voltage, 4);
        System.arraycopy(voltageBytes, 0, bytes, 7, voltageBytes.length);

        byte[] dischargeCountBytes = ByteUtil.fromInt(dischargeCount);
        System.arraycopy(dischargeCountBytes, 0, bytes, 9, dischargeCountBytes.length);

        bytes[11] = EC;
        xor(bytes);
        return bytes;
    }

    /**
     * Assign storage address
     *
     * @param bytes
     * @param address
     */
    private void assignAddress(byte[] bytes, int address) {
        bytes[3] = (byte) ((address & 0x0000FF00) >> 8);
        bytes[4] = (byte) ((address & 0x000000FF));
    }

    /**
     * Ack against host response
     *
     * @return
     */
    public byte[] ack() {
        return new byte[] {0x05};
    }

    private void xor(byte[] bytes) {
        byte xor = bytes[1];
        for (int i = 2; i < bytes.length - 2; i++) {
            xor ^= bytes[i];
        }
        bytes[bytes.length - 1] = xor;
    }

    public static void main(String[] args) {
        CommandWriter commandWriter = new CommandWriter();
//        System.out.println(ByteUtil.byte2hex(commandWriter.startDischarge(1)));
//        System.out.println(ByteUtil.byte2hex(commandWriter.stopDischarge(1)));
//        System.out.println(ByteUtil.byte2hex(commandWriter.timing(1)));
//        System.out.println(ByteUtil.byte2hex(commandWriter.collectRecord(1)));
//        System.out.println(ByteUtil.byte2hex(commandWriter.clearData(1)));

        System.out.println(ByteUtil.byte2hex(commandWriter.controlParam(1, 2, 12.32, 23.34, 999)));


    }
}
